package filechat;

//<editor-fold defaultstate="collapsed" desc="Imports">
import java.awt.event.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Calendar;
//</editor-fold>

public class GroupConnection implements ObjectStreamListener {
    //<editor-fold defaultstate="collapsed" desc="Variables Declaration">
    ArrayList<Socket> groupConnectionSockets;
    ArrayList<ObjectOutputStream> groupOutputStreams = new ArrayList();
    ArrayList<ObjectInputStream> groupInputStreams = new ArrayList();
    ArrayList<ObjectStreamManager> groupManagers = new ArrayList();
    String hostUsername;
    String contactUsernames;
    String inMessage;
    ChatWindow chatWindow;
    GroupChatActionListener actionListener = new GroupChatActionListener();
    String time;
    String receivedData;
    String inObject;
    int objectType;
    //</editor-fold>
    
    // GroupConnection constructor
    GroupConnection(ArrayList<Socket> sockets, String contactNames, String user) {
        hostUsername = user;
        contactUsernames = contactNames;
        groupConnectionSockets = sockets;
        
        // Create streams and managers for all sockets in the list
        for (int i = 0; i < groupConnectionSockets.size(); i++) {
            int number = i;
            try {
                groupOutputStreams.add(new ObjectOutputStream(groupConnectionSockets.get(i).getOutputStream()));       // Start output stream
                ObjectInputStream inStream = new ObjectInputStream(groupConnectionSockets.get(i).getInputStream());    // Start input stream
                groupInputStreams.add(inStream);
                groupManagers.add(new ObjectStreamManager(number, inStream, this));     // Start manager
            } catch (IOException e) {
                System.out.println("IOException: "+e.getMessage());
            }
        }
        startChatWindow();
    }
    
    //<editor-fold defaultstate="collapsed" desc="startChatWindow">
    // Starts a new ChatWindow and adds listeners
    void startChatWindow() {
        // Initiate chatWindow
        chatWindow = new ChatWindow();
        chatWindow.setTitle("Group Chat with: "+contactUsernames);
        // Add listeners to chatWindow components
        chatWindow.addWindowListener(new GroupChatWindowListener());
        chatWindow.writeArea.addKeyListener(new GroupChatKeyListener());
        chatWindow.sendButton.addActionListener(actionListener);
        chatWindow.clearButton.addActionListener(actionListener);
        chatWindow.sendFileButton.addActionListener(actionListener);
        chatWindow.sendFileMenuItem.addActionListener(actionListener);
        chatWindow.readArea.setAutoscrolls(true);
        chatWindow.writeArea.setAutoscrolls(true);
        // Make it visible
        chatWindow.setVisible(true);
        chatWindow.setLocationRelativeTo(chatWindow.getParent());
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="objectReceived">
    // Handles incoming objects
    @Override
    public void objectReceived(int number, Object object, Exception exception) {
        if (exception == null) {
            inObject = (String) object;
            objectType = checkObject(object);
            if (objectType == 1) {
                inMessage = inObject.split("\n")[1];
                chatWindow.readArea.append(inMessage+"\n");
                try {
                    checkConnections();
                    for (int k = 0; k < groupOutputStreams.size(); k++) {
                        groupOutputStreams.get(k).writeObject(1 + "\n" + inMessage);
                        groupOutputStreams.get(k).flush();
                    }
                } catch (IOException ex) {
                    chatWindow.readArea.append("ERROR! Could not send message"+"\n");
                }
                chatWindow.toFront();
            } else if (objectType == 4) {
                chatWindow.readArea.append(inObject.split("\n")[1]);
                try {
                    checkConnections();
                    for (int k = 0; k < groupOutputStreams.size(); k++) {
                        groupOutputStreams.get(k).writeObject(1 + "\n" + inMessage);
                        groupOutputStreams.get(k).flush();
                    }
                } catch (IOException ex) {
                    chatWindow.readArea.append("ERROR! Could not send message"+"\n");
                }
            }
        } else {
            System.out.println("exception in groupchat obj.rec. " + exception.getMessage());
        }
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="checkObject">
    // Used to check what kind of object is received
    public int checkObject(Object object) {
        try {
            receivedData = (String) object;
            return Integer.parseInt(receivedData.split("\n")[0]);
        } catch (Exception e) {
            System.out.println("checkObject exception: " + e.getMessage());
            return 0;
        }
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="sendGroupChatMessage">
    // Attempts to send a message to all connected clients
    void sendGroupChatMessage(boolean sendButton) {
        time = (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) + ":" + Calendar.getInstance().get(Calendar.MINUTE));
        if (!chatWindow.writeArea.getText().equals("")) {
            try {
                checkConnections();
                for (int k = 0; k < groupOutputStreams.size(); k++) {
                    groupOutputStreams.get(k).writeObject(1 + "\n" + "(" + time + ") " + hostUsername + ": " + chatWindow.writeArea.getText());
                    groupOutputStreams.get(k).flush();
                }
            } catch (IOException e) {
                chatWindow.readArea.append("(" + time + ") " + "ERROR! Could not send message"+"\n");
                chatWindow.writeArea.setText("");
            }
            // Adds a row break if the sendMessage() method is called from the send-button
            if (sendButton) {
                chatWindow.readArea.append("(" + time + ") " + hostUsername + ": " + chatWindow.writeArea.getText()+"\n");
            } else {
                chatWindow.readArea.append("(" + time + ") " + hostUsername + ": " + chatWindow.writeArea.getText());
            }
            chatWindow.writeArea.setText("");
        }
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="checkConnections">
    // Checks if anyone has disconnected
    void checkConnections() {
        for (int i= 0; i < groupConnectionSockets.size(); i++) {
            if (groupConnectionSockets.get(i).isClosed() || groupConnectionSockets.get(i) == null) {
                groupConnectionSockets.remove(i);
                groupOutputStreams.remove(i);
                groupManagers.remove(i);
            }
        }
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="closeConnections">
    // Attempts to close connections (sockets, managers and I/O streams)
    void closeConnections() {
        for (int i = 0; i < groupConnectionSockets.size(); i++) {
            if (!groupConnectionSockets.get(i).isClosed() || groupConnectionSockets.get(i) != null) {
                try {
                    groupConnectionSockets.get(i).close();
                    groupManagers.get(i).closeManager();
                    groupInputStreams.get(i).close();
                    groupOutputStreams.get(i).close();
                } catch (IOException e) {
                    System.err.println("Error in closing connection: " + e);
                }
            }
        }
    } //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="LISTENER CLASSES">
//*********************** INNER CLASSES / LISTENERS **************************\\
    // Listens for keyEvent==ENTER, and then runs method sendGroupChatMessage()
    private class GroupChatKeyListener extends KeyAdapter {
        @Override
        public void keyTyped(KeyEvent e) {
            if (e.getKeyChar() == KeyEvent.VK_ENTER) {
                sendGroupChatMessage(false);
            }
        }
    }
    // Listens for windowClosing events
    private class GroupChatWindowListener extends WindowAdapter {
        @Override
        public void windowClosing(WindowEvent e) {
            try {
                for (int k = 0; k < groupOutputStreams.size(); k++) {
                    groupOutputStreams.get(k).writeObject(4 + "\n" + "The host has disconnected" + "\n");
                    groupOutputStreams.get(k).flush();
                }
            } catch (IOException ex) {
                System.err.println(ex.getMessage());
            }
            closeConnections();
            e.getWindow().dispose();
        }
    }
    // Listens for button action events
    private class GroupChatActionListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource().equals(chatWindow.sendButton)) {
                sendGroupChatMessage(true);
            } else if (e.getSource().equals(chatWindow.clearButton)) {
                chatWindow.writeArea.setText("");
            } else if (e.getSource().equals(chatWindow.sendFileMenuItem) || e.getSource().equals(chatWindow.sendFileButton)) {
                chatWindow.readArea.append("File operations not yet supported!"+"\n");
                //                int returnVal = chatWindow.chatWindowFileChooser.showOpenDialog(chatWindow);
                //                if (returnVal == JFileChooser.APPROVE_OPTION) {
                //                    try {
                //                        sendFile(chatWindow.chatWindowFileChooser.getSelectedFile());
                //                    } catch (FileNotFoundException ex) {
                //                        System.out.println("filenotfoundexc.: "+ex.getMessage());
                //                    } catch (IOException ex) {
                //                        System.out.println("fileChooserIOexc.: "+ex.getMessage());
                //                    }
                //                } else {
                //                    System.out.println("I CROSE DAOWN!");
                //                }
            }
        }
    }
    //</editor-fold>
}